package com.ssy.lingxi.workflow.serviceimpl;

import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.workflow.api.model.vo.request.*;
import com.ssy.lingxi.workflow.api.model.vo.response.ComplexTaskCompleteVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleTaskCompleteVO;
import com.ssy.lingxi.workflow.entity.ExternalTaskDefinition;
import com.ssy.lingxi.workflow.entity.InternalTaskDefinition;
import com.ssy.lingxi.workflow.model.bo.KeyValueBO;
import com.ssy.lingxi.workflow.model.constant.ModelConstant;
import com.ssy.lingxi.workflow.model.constant.ProcessTaskTypeEnum;
import com.ssy.lingxi.workflow.model.constant.ProcessTypeEnum;
import com.ssy.lingxi.workflow.service.IExternalTaskDaoService;
import com.ssy.lingxi.workflow.service.IInternalTaskDaoService;
import com.ssy.lingxi.workflow.service.IProcessExecutionService;
import org.camunda.bpm.engine.RuntimeService;
import org.camunda.bpm.engine.TaskService;
import org.camunda.bpm.engine.runtime.ProcessInstance;
import org.camunda.bpm.engine.task.Task;
import org.camunda.bpm.engine.variable.VariableMap;
import org.camunda.bpm.engine.variable.Variables;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 流程启动、执行相关接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-04-26
 */
@Service
public class ProcessExecutionServiceImpl implements IProcessExecutionService {
    @Resource
    private TaskService taskService;

    @Resource
    private RuntimeService runtimeService;

    @Resource
    private IExternalTaskDaoService externalTaskDaoService;

    @Resource
    private IInternalTaskDaoService internalTaskDaoService;

    /**
     * 启动流程
     * @param startVO 接口参数
     * @return 启动结果
     */
    @Override
    public Wrapper<ComplexTaskCompleteVO> startProcess(TaskStartVO startVO) {
        //Step 1: 查询流程启动节点
        ExternalTaskDefinition startEventTask = externalTaskDaoService.findStartEvent(startVO.getProcessKey());
        if(startEventTask == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_DEFINITION_DOES_NOT_EXIST);
        }

        //设置流程参数
        String varName = String.format(ModelConstant.TASK_VARIABLE_NAME_FORMAT, startVO.getMemberId(), startVO.getRoleId());
        VariableMap variable = Variables.putValueTyped(varName, Variables.longValue(startVO.getDataId()));
        //启动流程
        ProcessInstance process = runtimeService.startProcessInstanceByKey(startVO.getProcessKey(), variable);

        //获取任务Id
        Task task = taskService.createTaskQuery().processInstanceId(process.getProcessInstanceId()).list().get(0);

        ComplexTaskCompleteVO completeVO = new ComplexTaskCompleteVO();
        completeVO.setTaskId(task.getId());

        if(startEventTask.getProcessType().equals(ProcessTypeEnum.COMPLEX_PROCESS.getCode()) || startEventTask.getProcessType().equals(ProcessTypeEnum.EXTERNAL_PROCESS.getCode())) {
            completeVO.setOuterStatus(startEventTask.getStatus());
            completeVO.setOuterStatusDesc(StringUtils.hasLength(startEventTask.getStatusDesc()) ? startEventTask.getStatusDesc() : "");
            completeVO.setOuterProperties(startEventTask.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));
        } else {
            completeVO.setInnerStatus(startEventTask.getStatus());
            completeVO.setInnerStatusDesc(StringUtils.hasLength(startEventTask.getStatusDesc()) ? startEventTask.getStatusDesc() : "");
            completeVO.setInnerProperties(startEventTask.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));
        }

        return Wrapper.success(completeVO);
    }

    /**
     * 启动流程后，执行第一个任务
     * @param startVO 接口参数
     * @return 执行结果
     */
    @Override
    public Wrapper<ComplexTaskCompleteVO> startProcessThenCompleteFirstTask(TaskStartVO startVO) {
        //Step 1: 查询流程启动节点
        ExternalTaskDefinition startEventTask = externalTaskDaoService.findStartEvent(startVO.getProcessKey());
        if(startEventTask == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_DEFINITION_DOES_NOT_EXIST);
        }

        //设置流程参数，启动流程
        String varName = String.format(ModelConstant.TASK_VARIABLE_NAME_FORMAT, startVO.getMemberId(), startVO.getRoleId());
        VariableMap variable = Variables.putValueTyped(varName, Variables.longValue(startVO.getDataId()));
        //启动流程
        ProcessInstance process = runtimeService.startProcessInstanceByKey(startVO.getProcessKey(), variable);

        //获取第一个任务，并完成任务。如果任务为Null，说明流程是一个空流程，只有StartEvent和EndEvent两个节点。返回StartEvent的属性值
        Task task = findNextTask(process.getProcessInstanceId());
        if(task == null) {
            ComplexTaskCompleteVO completeVO = new ComplexTaskCompleteVO();
            if(startEventTask.getProcessType().equals(ProcessTypeEnum.COMPLEX_PROCESS.getCode()) || startEventTask.getProcessType().equals(ProcessTypeEnum.EXTERNAL_PROCESS.getCode())) {
                completeVO.setOuterStatus(startEventTask.getStatus());
                completeVO.setOuterStatusDesc(StringUtils.hasLength(startEventTask.getStatusDesc()) ? startEventTask.getStatusDesc() : "");
                completeVO.setOuterProperties(startEventTask.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));
            } else {
                completeVO.setInnerStatus(startEventTask.getStatus());
                completeVO.setInnerStatusDesc(StringUtils.hasLength(startEventTask.getStatusDesc()) ? startEventTask.getStatusDesc() : "");
                completeVO.setInnerProperties(startEventTask.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));
            }
            return Wrapper.success(completeVO);
        }

        //查找当前Task的定义，判断跳转条件，并构建任务执行结果
        //第一个任务不能有跳转条件
        Wrapper<ComplexTaskCompleteVO> result = buildComplexTaskExecResult(startVO.getProcessKey(), task.getName(), ModelConstant.NO_AGREE);
        if(result.getCode() != ResponseCode.SUCCESS.getCode() || result.getData() == null) {
            return result;
        }

        //执行第一个任务
        taskService.complete(task.getId());

        //查找下一个任务，如果流程已经执行完毕，下一个任务为Null
        Task nextTask = findNextTask(process.getProcessInstanceId());
        ComplexTaskCompleteVO completeVO = result.getData();
        completeVO.setTaskId(nextTask == null ? "" : nextTask.getId());
        return Wrapper.success(completeVO);
    }

    /**
     * 执行流程步骤
     *
     * @param executeVO 接口参数
     * @return 执行结果
     */
    @Override
    public Wrapper<ComplexTaskCompleteVO> completeTask(TaskExecuteVO executeVO) {
        //查找Task（如果已经执行过了或TaskId不正确，Task会为null）
        Task task = taskService.createTaskQuery().taskId(executeVO.getTaskId()).active().singleResult();
        if(task == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_DOEX_NOT_EXIST_OR_COMPLETED);
        }

        //查找当前Task的定义，判断跳转条件，并构建任务执行结果
        Wrapper<ComplexTaskCompleteVO> result = buildComplexTaskExecResult(executeVO.getProcessKey(), task.getName(), executeVO.getAgree());
        if(result.getCode() != ResponseCode.SUCCESS.getCode() || result.getData() == null) {
            return Wrapper.fail(result.getCode(), result.getMessage());
        }

        //记录当前流程实例的Id
        String processInstanceId = task.getProcessInstanceId();

        //执行任务
        if(executeVO.getAgree() != null && executeVO.getAgree() >= 0) {
            Map<String, Object> jumpVar = new HashMap<>();
            jumpVar.put(ModelConstant.TASK_JUMP_VAR_KEY, executeVO.getAgree());
            taskService.complete(task.getId(), jumpVar);
        } else {
            taskService.complete(task.getId());
        }

        //查找下一个任务，如果流程已经执行完毕，下一个任务为Null
        Task nextTask = findNextTask(processInstanceId);
        ComplexTaskCompleteVO completeVO = result.getData();
        completeVO.setTaskId(nextTask == null ? "" : nextTask.getId());
        return Wrapper.success(completeVO);
    }

    /**
     * 连续执行流程步骤
     *
     * @param executeVO 接口参数
     * @return 执行结果
     */
    @Override
    public Wrapper<ComplexTaskCompleteVO> completeSerialTasks(SerialTaskExecuteVO executeVO) {
        //查找Task（如果已经执行过了或TaskId不正确，Task会为null）
        Task task = taskService.createTaskQuery().taskId(executeVO.getTaskId()).active().singleResult();
        if(task == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_DOEX_NOT_EXIST_OR_COMPLETED);
        }

        if(CollectionUtils.isEmpty(executeVO.getAgrees()) || executeVO.getAgrees().size() != executeVO.getExecTimes()) {
            return Wrapper.fail(ResponseCode.WF_TASK_JUMP_PARAMETER_SIZE_NOT_EQUAL_TO_EXEC_TIMES);
        }

        //记录当前流程实例的Id
        String processInstanceId = task.getProcessInstanceId();

        //查找当前Task的定义，判断跳转条件，并构建任务执行结果
        Wrapper<ComplexTaskCompleteVO> result = new Wrapper<>();

        //连续执行任务
        for (int i = 0; i < executeVO.getExecTimes(); i++) {
            if(task == null) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_DOEX_NOT_EXIST_OR_COMPLETED);
            }

            Integer jumpParameter = executeVO.getAgrees().get(i);

            if(i == executeVO.getExecTimes() - 1) {
                result = buildComplexTaskExecResult(executeVO.getProcessKey(), task.getName(), jumpParameter);
                if(result.getCode() != ResponseCode.SUCCESS.getCode() || result.getData() == null) {
                    return Wrapper.fail(result.getCode(), result.getMessage());
                }
            }

            if(jumpParameter != null && jumpParameter >= 0) {
                Map<String, Object> jumpVar = new HashMap<>();
                jumpVar.put(ModelConstant.TASK_JUMP_VAR_KEY, jumpParameter);
                taskService.complete(task.getId(), jumpVar);
            } else {
                taskService.complete(task.getId());
            }

            //查找下一个任务，如果流程已经执行完毕，下一个任务为Null
            task = findNextTask(processInstanceId);
            if(task == null && i < executeVO.getExecTimes() - 1) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_DOEX_NOT_EXIST_OR_COMPLETED);
            }
        }

        //查找下一个任务，如果流程已经执行完毕，下一个任务为Null
        ComplexTaskCompleteVO completeVO = result.getData();
        completeVO.setTaskId(task == null ? "" : task.getId());
        return Wrapper.success(completeVO);
    }

    /**
     * 启动单一的外部流程或内部流程
     *
     * @param startVO 接口参数
     * @return 启动结果
     */
    @Override
    public Wrapper<SimpleTaskCompleteVO> startSimpleProcess(TaskStartVO startVO) {
        //Step 1: 查询流程启动节点
        ExternalTaskDefinition startEventTask = externalTaskDaoService.findStartEvent(startVO.getProcessKey());
        if(startEventTask == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_DEFINITION_DOES_NOT_EXIST);
        }

        //如果是复杂流程，返回错误提示：
        if(startEventTask.getProcessType().equals(ProcessTypeEnum.COMPLEX_PROCESS.getCode())) {
            return Wrapper.fail(ResponseCode.WF_NEED_CALL_COMPLEX_PROCESS_API);
        }

        //设置流程参数：与复杂流程不同，这里将流程类型设置到流程参数里面，用于在执行任务的时候进行判断
        String varName = String.format(ModelConstant.TASK_VARIABLE_NAME_FORMAT, startVO.getMemberId(), startVO.getRoleId());
        VariableMap variable = Variables.putValueTyped(varName, Variables.longValue(startVO.getDataId()))
                .putValueTyped(ModelConstant.PROCESS_TYPE_VARIABLE_NAME, Variables.integerValue(startEventTask.getProcessType()));
        //启动流程
        ProcessInstance process = runtimeService.startProcessInstanceByKey(startVO.getProcessKey(), variable);

        //获取下一个任务，如果下一个任务为null，说明流程是一个空流程，此时流程已经执行完毕
        Task task = findNextTask(process.getProcessInstanceId());
        SimpleTaskCompleteVO completeVO = new SimpleTaskCompleteVO();
        completeVO.setTaskId(task == null ? "" : task.getId());
        completeVO.setStatus(startEventTask.getStatus());
        completeVO.setStatusDesc(StringUtils.hasLength(startEventTask.getStatusDesc()) ? startEventTask.getStatusDesc() : "");
        completeVO.setStep(startEventTask.getTaskStep());
        completeVO.setProperties(startEventTask.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));

        return Wrapper.success(completeVO);
    }

    /**
     * 启动单一的外部流程或内部流程，并执行第一个步骤
     * @param startVO 接口参数
     * @return 执行结果
     */
    @Override
    public Wrapper<SimpleTaskCompleteVO> startSimpleProcessThenCompleteFirstTask(TaskStartVO startVO) {
        //Step 1: 查询流程启动节点
        ExternalTaskDefinition startEventTask = externalTaskDaoService.findStartEvent(startVO.getProcessKey());
        if(startEventTask == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_DEFINITION_DOES_NOT_EXIST);
        }

        //如果是复杂流程，返回错误提示
        if(startEventTask.getProcessType().equals(ProcessTypeEnum.COMPLEX_PROCESS.getCode())) {
            return Wrapper.fail(ResponseCode.WF_NEED_CALL_COMPLEX_PROCESS_API);
        }

        //设置流程参数：与复杂流程不同，这里将流程类型设置到流程参数里面，用于在执行任务的时候进行判断
        String varName = String.format(ModelConstant.TASK_VARIABLE_NAME_FORMAT, startVO.getMemberId(), startVO.getRoleId());
        VariableMap variable = Variables.putValueTyped(varName, Variables.longValue(startVO.getDataId()))
                .putValueTyped(ModelConstant.PROCESS_TYPE_VARIABLE_NAME, Variables.integerValue(startEventTask.getProcessType()));
        //启动流程
        ProcessInstance process = runtimeService.startProcessInstanceByKey(startVO.getProcessKey(), variable);

        //获取第一个任务，并完成任务。如果任务为Null，说明流程是一个空流程，只有StartEvent和EndEvent两个节点。
        Task task = findNextTask(process.getProcessInstanceId());
        if(task == null) {
            SimpleTaskCompleteVO completeVO = new SimpleTaskCompleteVO();
            completeVO.setTaskId("");
            completeVO.setStatus(startEventTask.getStatus());
            completeVO.setStatusDesc(StringUtils.hasLength(startEventTask.getStatusDesc()) ? startEventTask.getStatusDesc() : "");
            completeVO.setStep(startEventTask.getTaskStep());
            completeVO.setProperties(startEventTask.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));
            return Wrapper.success(completeVO);
        }

        Wrapper<SimpleTaskCompleteVO> result = startEventTask.getProcessType().equals(ProcessTypeEnum.EXTERNAL_PROCESS.getCode()) ? buildSimpleExternalTaskExecResult(startVO.getProcessKey(), task.getName(), ModelConstant.NO_AGREE) : buildSimpleInternalTaskExecResult(startVO.getProcessKey(), task.getName(), ModelConstant.NO_AGREE);
        if(result.getCode() != ResponseCode.SUCCESS.getCode() || result.getData() == null) {
            return Wrapper.fail(result.getCode(), result.getMessage());
        }

        //执行第一个任务
        taskService.complete(task.getId());
        Task nextTask = findNextTask(process.getProcessInstanceId());
        SimpleTaskCompleteVO completeVO = result.getData();
        completeVO.setTaskId(nextTask == null ? "" : nextTask.getId());

        return Wrapper.success(completeVO);
    }


    /**
     * 执行单一的外部流程、或内部流程
     *
     * @param executeVO 接口参数
     * @return 执行结果
     */
    @Override
    public Wrapper<SimpleTaskCompleteVO> completeSimpleTask(TaskExecuteVO executeVO) {
        //查找Task（如果已经执行过了或TaskId不正确，Task会为null）
        Task task = taskService.createTaskQuery().taskId(executeVO.getTaskId()).active().singleResult();
        if(task == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_DOEX_NOT_EXIST_OR_COMPLETED);
        }

        //获取流程参数中的流程类型
        Integer processType = Integer.parseInt(String.valueOf(runtimeService.getVariable(task.getExecutionId(), ModelConstant.PROCESS_TYPE_VARIABLE_NAME)));
        //记录当前流程实例的Id
        String processInstanceId = task.getProcessInstanceId();

        //查找当前Task的定义，判断跳转条件，并构建任务执行结果
        Wrapper<SimpleTaskCompleteVO> result = processType.equals(ProcessTypeEnum.EXTERNAL_PROCESS.getCode()) ? buildSimpleExternalTaskExecResult(executeVO.getProcessKey(), task.getName(), executeVO.getAgree()) : buildSimpleInternalTaskExecResult(executeVO.getProcessKey(), task.getName(), executeVO.getAgree());
        if(result.getCode() != ResponseCode.SUCCESS.getCode() || result.getData() == null) {
            return Wrapper.fail(result.getCode(), result.getMessage());
        }

        //执行任务
        if(executeVO.getAgree() != null && executeVO.getAgree() >=0 ) {
            Map<String, Object> jumpVar = new HashMap<>();
            jumpVar.put(ModelConstant.TASK_JUMP_VAR_KEY, executeVO.getAgree());
            taskService.complete(task.getId(), jumpVar);
        } else {
            taskService.complete(task.getId());
        }

        //查找下一个任务，如果流程已经执行完毕，下一个任务为Null
        Task nextTask = findNextTask(processInstanceId);
        SimpleTaskCompleteVO completeVO = result.getData();
        completeVO.setTaskId(nextTask == null ? "" : nextTask.getId());

        return Wrapper.success(completeVO);
    }

    /**
     * 查询流程参数
     *
     * @param queryVO 接口参数
     * @return 参数列表
     */
    @Override
    public Wrapper<List<Long>> findProcessDataIds(ProcessDataQueryVO queryVO) {
        List<ExternalTaskDefinition> externalTaskDefinitions = externalTaskDaoService.findByProcessKey(queryVO.getProcessKey());
        if(CollectionUtils.isEmpty(externalTaskDefinitions)) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_DEFINITION_DOES_NOT_EXIST);
        }

        //三种查询：
        List<String> taskNames = new ArrayList<>();
        if(queryVO.getTaskStep() != null && queryVO.getTaskStep() > 0 && queryVO.getStatus() != null && queryVO.getStatus() > 0) {
            taskNames = externalTaskDefinitions.stream().filter(extTask -> extTask.getTaskStep().equals(queryVO.getTaskStep()) && extTask.getStatus().equals(queryVO.getStatus())).map(ExternalTaskDefinition::getTaskName).distinct().collect(Collectors.toList());
            taskNames.addAll(externalTaskDefinitions.stream().filter(extTask -> !CollectionUtils.isEmpty(extTask.getSubTasks())).flatMap(extTask -> extTask.getSubTasks().stream()).filter(intTask -> intTask.getTaskStep().equals(queryVO.getTaskStep()) && intTask.getStatus().equals(queryVO.getStatus())).map(InternalTaskDefinition::getTaskName).distinct().collect(Collectors.toList()));
            if(CollectionUtils.isEmpty(taskNames)) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_STEP_OR_STATUS_INCORRECT);
            }
        } else if(queryVO.getTaskStep() != null && queryVO.getTaskStep() > 0) {
            taskNames = externalTaskDefinitions.stream().filter(extTask -> extTask.getTaskStep().equals(queryVO.getTaskStep())).map(ExternalTaskDefinition::getTaskName).distinct().collect(Collectors.toList());
            taskNames.addAll(externalTaskDefinitions.stream().filter(extTask -> !CollectionUtils.isEmpty(extTask.getSubTasks())).flatMap(extTask -> extTask.getSubTasks().stream()).filter(intTask -> intTask.getTaskStep().equals(queryVO.getTaskStep())).map(InternalTaskDefinition::getTaskName).distinct().collect(Collectors.toList()));
            if(CollectionUtils.isEmpty(taskNames)) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_STEP_INCORRECT);
            }
        } else if(queryVO.getStatus() != null && queryVO.getStatus() >0) {
            taskNames = externalTaskDefinitions.stream().filter(extTask -> extTask.getStatus().equals(queryVO.getStatus())).map(ExternalTaskDefinition::getTaskName).distinct().collect(Collectors.toList());
            taskNames.addAll(externalTaskDefinitions.stream().filter(extTask -> !CollectionUtils.isEmpty(extTask.getSubTasks())).flatMap(extTask -> extTask.getSubTasks().stream()).filter(intTask -> intTask.getStatus().equals(queryVO.getStatus())).map(InternalTaskDefinition::getTaskName).distinct().collect(Collectors.toList()));
            if(CollectionUtils.isEmpty(taskNames)) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_STATUS_INCORRECT);
            }
        }

        String varName = String.format(ModelConstant.TASK_VARIABLE_NAME_FORMAT, queryVO.getMemberId(), queryVO.getRoleId());
        List<Task> tasks = taskService.createTaskQuery().processDefinitionKey(queryVO.getProcessKey()).processVariableValueGreaterThanOrEquals(varName, 0L).list();
        if(CollectionUtils.isEmpty(tasks)) {
            return Wrapper.success(new ArrayList<>());
        }

        List<String> finalTaskNames = taskNames;
        List<String> processInstanceIds = CollectionUtils.isEmpty(taskNames) ? tasks.stream().map(Task::getProcessInstanceId).distinct().collect(Collectors.toList()) : tasks.stream().filter(t -> finalTaskNames.contains(t.getName())).map(Task::getProcessInstanceId).distinct().collect(Collectors.toList());
        if(CollectionUtils.isEmpty(processInstanceIds)) {
            return Wrapper.success(new ArrayList<>());
        }

        String[] instanceIds = new String[processInstanceIds.size()];
        List<Long> dataIds = runtimeService.createVariableInstanceQuery().variableName(varName).processInstanceIdIn(processInstanceIds.toArray(instanceIds)).list().stream().map(p -> Long.parseLong(String.valueOf(p.getValue()))).collect(Collectors.toList());
        return Wrapper.success(dataIds);
    }

    /**
     * 根据任务Id，（异步）删除流程实例
     *
     * @param taskIdVO 接口参数
     */
    @Override
    public void deleteProcessInstance(TaskIdVO taskIdVO) {
        Task task = taskService.createTaskQuery().taskId(taskIdVO.getTaskId()).active().singleResult();
        if(task == null) {
            return;
        }

        runtimeService.deleteProcessInstanceIfExists(task.getProcessInstanceId(), "", true, true, true, true);
    }

    /**
     * 执行复杂流程，查找当前任务（外部或内部），判断跳转条件，返回status、自定义属性等信息
     * @param processKey 流程的Key
     * @param taskName  任务名称
     * @return 任务执行结果的部分字段赋值
     */
    private Wrapper<ComplexTaskCompleteVO> buildComplexTaskExecResult(String processKey, String taskName, Integer agree) {
        ComplexTaskCompleteVO completeVO = new ComplexTaskCompleteVO();
        //这里是先查找外部任务，再查找内部任务
        //可以调换查找顺序
        List<ExternalTaskDefinition> externalTaskDefinitions = externalTaskDaoService.findByProcessKeyAndTaskNameAndTaskType(processKey, taskName, ProcessTaskTypeEnum.USER_TASK.getCode());
        if(!CollectionUtils.isEmpty(externalTaskDefinitions)) {
            Wrapper<Void> result = buildExternalTaskRuntimeProperties(externalTaskDefinitions, agree, completeVO);
            return result.getCode() == ResponseCode.SUCCESS.getCode() ? Wrapper.success(completeVO) : Wrapper.fail(result.getCode(), result.getMessage());
        }

        List<InternalTaskDefinition> internalTaskDefinitions = internalTaskDaoService.findByProcessKeyAndTaskNameAndTaskType(processKey, taskName, ProcessTaskTypeEnum.USER_TASK.getCode());
        if(CollectionUtils.isEmpty(internalTaskDefinitions)) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_DEFINITION_DOES_NOT_EXIST);
        }

        Wrapper<Void> result = buildInternalTaskRuntimeProperties(internalTaskDefinitions, agree, completeVO);
        return result.getCode() == ResponseCode.SUCCESS.getCode() ? Wrapper.success(completeVO) : Wrapper.fail(result.getCode(), result.getMessage());
    }

    /**
     * 从外部任务定义列表中判断跳转条件、并返回状态、状态描述、自定义属性
     * @param externalTaskDefinitions  外部任务定义列表
     * @param agree  接口传递的跳转条件
     * @param completeVO 返回的结果
     */
    private Wrapper<Void> buildExternalTaskRuntimeProperties(List<ExternalTaskDefinition> externalTaskDefinitions, Integer agree, ComplexTaskCompleteVO completeVO) {
        if(CollectionUtils.isEmpty(externalTaskDefinitions)) {
            return Wrapper.success();
        }

        List<Integer> agrees = externalTaskDefinitions.stream().filter(extTask -> extTask.getAgree() != null && extTask.getAgree() >= 0).map(ExternalTaskDefinition::getAgree).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(agrees)) {
           if(agree != null && agree >= 0) {
               return Wrapper.fail(ResponseCode.WF_PROCESS_AGREE_PRAMETER_IS_NOT_MATCH);
           }
        } else {
            if(agree == null || agree < 0 || !agrees.contains(agree)) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_AGREE_PRAMETER_IS_NOT_MATCH);
            }
        }

        ExternalTaskDefinition externalTaskDefinition = agree == null || agree < 0 ? externalTaskDefinitions.get(0) : externalTaskDefinitions.stream().filter(extTask -> extTask.getAgree().equals(agree)).findFirst().orElse(null);
        if(externalTaskDefinition == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_NOT_EXIST);
        }

        completeVO.setOuterStep(externalTaskDefinition.getTaskStep());
        completeVO.setOuterStatus(externalTaskDefinition.getStatus());
        completeVO.setOuterStatusDesc(StringUtils.hasLength(externalTaskDefinition.getStatusDesc()) ? externalTaskDefinition.getStatusDesc() : "");
        completeVO.setOuterProperties(externalTaskDefinition.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));

        return Wrapper.success();
    }

    /**
     * 从内部任务定义列表中判断跳转条件、返回状态、状态描述、自定义属性
     * @param internalTaskDefinitions 内部任务定义列表
     * @param agree 接口传递的跳转条件
     * @param completeVO 返回结果
     */
    private Wrapper<Void> buildInternalTaskRuntimeProperties(List<InternalTaskDefinition> internalTaskDefinitions, Integer agree, ComplexTaskCompleteVO completeVO) {
        if(CollectionUtils.isEmpty(internalTaskDefinitions)) {
            return Wrapper.success();
        }

        List<Integer> agrees = internalTaskDefinitions.stream().filter(intTask -> intTask.getAgree() != null && intTask.getAgree() >= 0).map(InternalTaskDefinition::getAgree).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(agrees)) {
            if(agree != null && agree >= 0) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_AGREE_PRAMETER_IS_NOT_MATCH);
            }
        } else {
            if(agree == null || agree < 0 || !agrees.contains(agree)) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_AGREE_PRAMETER_IS_NOT_MATCH);
            }
        }

        InternalTaskDefinition internalTaskDefinition = agree == null || agree < 0 ? internalTaskDefinitions.get(0) : internalTaskDefinitions.stream().filter(intTask -> intTask.getAgree().equals(agree)).findFirst().orElse(null);
        if(internalTaskDefinition != null) {
            completeVO.setInnerStep(internalTaskDefinition.getTaskStep());
            completeVO.setInnerStatus(internalTaskDefinition.getStatus());
            completeVO.setInnerStatusDesc(internalTaskDefinition.getStatusDesc());
            completeVO.setInnerProperties(internalTaskDefinition.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));

            ExternalTaskDefinition externalTaskDefinition = internalTaskDefinition.getExtTask();
            if (externalTaskDefinition != null) {
                completeVO.setOuterStep(externalTaskDefinition.getTaskStep());
                completeVO.setOuterStatus(externalTaskDefinition.getStatus());
                completeVO.setOuterStatusDesc(StringUtils.hasLength(externalTaskDefinition.getStatusDesc()) ? externalTaskDefinition.getStatusDesc() : "");
                completeVO.setOuterProperties(externalTaskDefinition.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));
            }
        }

        return Wrapper.success();
    }

    /**
     * 执行单一的外部流程时，从外部任务定义列表中判断跳转条件、返回状态、状态描述、自定义属性
     * @param processKey 流程的Key
     * @param taskName 要执行的任务的名称
     * @param agree 流程跳转条件
     * @return 要执行的任务的属性
     */
    private Wrapper<SimpleTaskCompleteVO> buildSimpleExternalTaskExecResult(String processKey, String taskName, Integer agree) {
        List<ExternalTaskDefinition> externalTaskDefinitions = externalTaskDaoService.findByProcessKeyAndTaskNameAndTaskType(processKey, taskName, ProcessTaskTypeEnum.USER_TASK.getCode());
        if(CollectionUtils.isEmpty(externalTaskDefinitions)) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_DEFINITION_DOES_NOT_EXIST);
        }

        List<Integer> agrees = externalTaskDefinitions.stream().filter(extTask -> extTask.getAgree() != null && extTask.getAgree() >= 0).map(ExternalTaskDefinition::getAgree).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(agrees)) {
            if(agree != null && agree >= 0) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_AGREE_PRAMETER_IS_NOT_MATCH);
            }
        } else {
            if(agree == null || agree < 0 || !agrees.contains(agree)) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_AGREE_PRAMETER_IS_NOT_MATCH);
            }
        }

        ExternalTaskDefinition externalTaskDefinition = agree == null || agree < 0 ? externalTaskDefinitions.get(0) : externalTaskDefinitions.stream().filter(extTask -> extTask.getAgree().equals(agree)).findFirst().orElse(null);
        if(externalTaskDefinition == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_TASK_NOT_EXIST);
        }

        SimpleTaskCompleteVO completeVO = new SimpleTaskCompleteVO();
        completeVO.setStep(externalTaskDefinition.getTaskStep());
        completeVO.setStatus(externalTaskDefinition.getStatus());
        completeVO.setStatusDesc(StringUtils.hasLength(externalTaskDefinition.getStatusDesc()) ? externalTaskDefinition.getStatusDesc() : "");
        completeVO.setProperties(externalTaskDefinition.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));

        return Wrapper.success(completeVO);
    }

    /**
     * 执行单一的内部流程时，从内部任务定义列表中判断跳转条件、返回状态、状态描述、自定义属性
     * @param processKey 流程的Key
     * @param taskName 要执行的任务的名称
     * @param agree 流程跳转条件
     * @return 要执行的任务的属性
     */
    private Wrapper<SimpleTaskCompleteVO> buildSimpleInternalTaskExecResult(String processKey, String taskName, Integer agree) {
        List<InternalTaskDefinition> internalTaskDefinitions = internalTaskDaoService.findByProcessKeyAndTaskNameAndTaskType(processKey, taskName, ProcessTaskTypeEnum.USER_TASK.getCode());
        if(CollectionUtils.isEmpty(internalTaskDefinitions)) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_DEFINITION_DOES_NOT_EXIST);
        }

        List<Integer> agrees = internalTaskDefinitions.stream().filter(intTask -> intTask.getAgree() != null && intTask.getAgree() >= 0).map(InternalTaskDefinition::getAgree).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(agrees)) {
            if(agree != null && agree >= 0) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_AGREE_PRAMETER_IS_NOT_MATCH);
            }
        } else {
            if(agree == null || agree < 0 || !agrees.contains(agree)) {
                return Wrapper.fail(ResponseCode.WF_PROCESS_AGREE_PRAMETER_IS_NOT_MATCH);
            }
        }

        InternalTaskDefinition internalTaskDefinition = agree == null || agree < 0 ? internalTaskDefinitions.get(0) : internalTaskDefinitions.stream().filter(intTask -> intTask.getAgree().equals(agree)).findFirst().orElse(null);
        if(internalTaskDefinition == null) {
            return Wrapper.fail(ResponseCode.WF_PROCESS_AGREE_PRAMETER_IS_NOT_MATCH);
        }

        SimpleTaskCompleteVO completeVO = new SimpleTaskCompleteVO();
        completeVO.setStep(internalTaskDefinition.getTaskStep());
        completeVO.setStatus(internalTaskDefinition.getStatus());
        completeVO.setStatusDesc(StringUtils.hasLength(internalTaskDefinition.getStatusDesc()) ? internalTaskDefinition.getStatusDesc() : "");
        completeVO.setProperties(internalTaskDefinition.getOther().stream().collect(Collectors.toMap(KeyValueBO::getKey, KeyValueBO::getValue)));
        return Wrapper.success(completeVO);
    }

    /**
     * 根据流程实例Id，查找下一个任务
     * @param processInstanceId 流程实例Id
     * @return 下一个任务，如果流程已经执行完毕，返回Null
     */
    private Task findNextTask(String processInstanceId) {
        return taskService.createTaskQuery().processInstanceId(processInstanceId).active().singleResult();
    }
}
